package Machine;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.JsonParseException;
import org.codehaus.jackson.map.JsonMappingException;
import org.codehaus.jackson.map.ObjectMapper;

import experiments.*;
import system.*;

public class VirtualMachine {
	private String VMName;
	private String vnet;
	private String diskName;
	private boolean firstTier=false;
	private boolean inputController=false;
	private String hostFakeName;
	private PhysicalMachine PM;
	private Application app;

	public Metric metric=null;
	public Metric metricOld=null;
	public Metric newMetric;

	public double CPUAllocReq;
	public double CPUIFAllocReq;

	public VirtualMachine(String VMName,String diskName, PhysicalMachine PM, Application app){
		this.VMName=VMName;
		this.diskName=diskName;
		this.PM=PM;
		this.app=app;

		String VNET=openURL("http://"+PM.getHostIP()+":9111/vcontrol/vm/"+VMName+"/net/rate");
		openURL("http://"+PM.getHostIP()+":9111/vcontrol/vm/"+VMName+"/cpu/share/"+1000);
		this.vnet=VNET.substring(0,VNET.indexOf(','));

		pinCPU(PM.getHostIP(),VMName,0);
		singleLevelConverge.addVM(this);
		PM.addVM(this);
		app.addVM(this);
	}

	public void Migrate(String newhostIP,PhysicalMachine newPM) throws JsonParseException, JsonMappingException, MalformedURLException, IOException{
		ObjectMapper mapper = new ObjectMapper();
		JsonNode migrate=mapper.readValue(new URL("http://"+this.PM.getHostIP()+"/vcontrol/vm/"+this.VMName+"/migrate?uri=qemu%2Bssh://"+newPM.getHostIP()+"/system"), JsonNode.class);
		if (migrate.get("success").toString()=="true"){
			PM.removeVM(this);
			newPM.addVM(this);
			String VNET=openURL("http://"+this.PM.getHostIP()+":9111/vcontrol/vm/"+VMName+"/net/rate");
			this.vnet=VNET.substring(0,VNET.indexOf(','));
			pinCPU(PM.getHostIP(),VMName,0);
		}
	}

	public String getVMName(){
		return this.VMName;
	}

	public String getVnet(){
		return this.vnet;
	}

	public String getDiskName(){
		return this.diskName;
	}

	public Metric getMetric(){
		return this.metric;
	}

	public void nullNewMetric(){
		this.newMetric=null;
	}

	public void setNewMetric(Metric metric){
		this.newMetric=metric;
	}

	public Metric getNewMetric(){
		return this.newMetric;
	}

	public void newMetricToMetric(){
		if (this.metric!=null)
		this.metricOld=this.metric.clone();
		this.metric=this.newMetric.clone();
	}

	public boolean isFirstTier(){
		return this.firstTier;
	}

	public void setFirstTier(){
		this.firstTier=true;
	}
	
	public void pinCPU(String hostIP, String VMName, int CPUnum){
		openURL("http://"+hostIP+":9111/vcontrol/vm/"+VMName+"/cpu/pin?cpu=0&pin="+Integer.toString(CPUnum));
	}
	
	public void setInputController(){
		this.inputController=true;
	}
	
	public boolean useInputController(){
		return this.inputController;
	}
	
	public String getHostFakeName(){
		return this.hostFakeName;
	}
	
	public void setHostFakeName(String name){
		this.hostFakeName=name;
	}
	
	private static String openURL(String urlString){
		String ret = null;
		try{
			URL url = new URL(urlString);
			BufferedReader br = new BufferedReader(new InputStreamReader(url.openStream()));

			ret = br.readLine();
		}
		catch(Exception e){
			e.printStackTrace();
		}
		return ret;
	}
	
	public PhysicalMachine getPM(){
		return this.PM;
	}
	
	public void setCPUReq(double CPU){
		this.CPUAllocReq=CPU;
	}
	public void setCPUIFReq(double CPU){
		this.CPUIFAllocReq=CPU;
	}
	public double getCPUReq(){
		return this.CPUAllocReq;
	}
	public double getCPUIFReq(){
		return this.CPUIFAllocReq;
	}
}


